#include <iostream>
#include <memory>
using namespace std;

/*
    C++多态详解
        C++多态是C++面向对象的三大特性之一，另外两个为封装和继承。
*/

/*
    C++多态
        多态性是指当不同对象收到相同的消息时产生不同的动作
    多态的形式
        C++支持两种形式的多态性：
        第一种是编译时多态，称为静态联编。是指程序在编译前确定的多态性，是通过重载机制来实现的包括：函数重载和运算符重载。
        第二种是运行时多态，称为动态联编。是指必须在运行中才可以确定的多态性，是通过继承和虚函数来实现的，这里一般指重写。
*/

/*
    函数重载个重写的区别

    1 虚函数是基类希望派生类重新定义的函数，派生类重新定义基类虚函数的做法叫做覆盖（重写）；

    2 重载就在允许在相同作用域中存在多个同名的函数，这些函数的参数表不同。重载的概念不属于面向对象编程，编译器根据函数不同的形参表对同名函数的名称做修饰，然后这些同名函数就成了不同的函数。

    3 重载的确定是在编译时确定，是静态的；虚函数则是在运行时动态确定。


*/

/*
    虚函数：在类的成员函数前加virtual关键字。
        虚函数是实现多态的基础。一旦基类定义了虚函数，该基类的派生类中的同名函数也自动称为虚函数。
    
    虚函数的重写：派生类中有一个跟基类的完全相同的虚函数，我们就称子类的虚函数重写了基类的虚函数。
        “完全相同”是指：函数名、参数、返回值都相同。另外，虚函数的重写也叫做虚函数的覆盖。
*/

/*
    纯虚函数：
        在虚函数的后面写上 = 0，则这个函数为纯虚函数。（纯虚函数没有函数体）
        包含纯虚函数的类叫做抽象类（也叫接口类），抽象类不能实例化出对象。派生类继承后也不能实例化出对象。
        只有重写纯虚函数，派生类才能实例化出对象。纯虚函数规范了派生类必须重写，另外纯虚函数更体现了接口继承。

*/

/*
    子类和父类的实例化关系：
    子类可以实例化成父类，父类不能实例化成子类，因为子类可能重写了父类，子类的范畴是大于父类的，大到小是可以的，小到大是不行的
*/

/*
    静态绑定又称为前期绑定(早绑定)，在程序编译期间确定了程序的行为，也称为静态多态，比如：函数重载。
    动态绑定又称后期绑定(晚绑定)，是在程序运行期间，根据具体拿到的类型确定程序的具体行为，调用具体的函数，也称为动态多态。
*/


// 函数重载
namespace TR
{
    class Person
    {
        public:
            int add(int a,int b)
            {
                cout << "整数相加" << endl;
                return (a+b);
            };
            
            // 函数重载
            float add(float a,float b)
            {
                cout << "浮点数相加" << endl;
                return (a+b);
            };
        private:
            int id;
    };

};

namespace TR1
{
    class Person
    {
        public:
            virtual void Display()
            {
                cout << "我是基类" << endl;
            }
            virtual void show()
            {
                cout << "Person show() function" << endl;
            }
    };

    class Student : public Person
    {
        public:
            // 这里不加virtual，默认也是有的
            virtual void Display() override {
                cout << "我是派生类" << endl;
            }
            virtual void show()
            {
                cout << "Student show() function" << endl;
            }
    };
};


int sub(int a,int b)
{
    return (a-b);
}

// 定义函数指针
typedef int (*FUNC)(int,int);


int main(int argc, char *argv[])
{
    // 函数重载，实现多态
    {
        using namespace TR;

        Person * july = new Person();
        cout << "int add: " << july->add(1,2) << endl;
        cout << "float add: " << july->add((float)1.2,(float)2.3) << endl;

        delete july;
        
        cout << "Person TR 大小： " << sizeof(Person) << endl; // 仅仅只有一个int型的变量，大小为4个字节，没有虚函数
    }

    // 函数的重写，实现多态
    {
        using namespace TR1;
        std::shared_ptr<Person> p = std::make_shared<Student>();
	    p->Display();
        p->show();
        cout << "Person TR1 大小： " << sizeof(Person) << endl; // 存在虚函数表地址，因此有一个虚函数表指针 大小为8个字节

        
    }

    // 函数指针的使用
    {
        // int (*func)(int ,int);
        
        
        FUNC func = sub;
        cout << func(4,3) << endl;
    }
    

    
    



    return 0;
}



